<template>
  <Teleport to="body">
    <div class="slide-split">
      <div class="slider-container" :style="{ width: bigWidth + 'px' }">
        <div
          class="slider-canvas"
          :style="{ width: bigWidth + 'px', height: bigHeight + 'px' }"
        >
          <!-- 大图 -->
          <canvas
            :width="bigWidth"
            :height="bigHeight"
            ref="bigCanvas"
          ></canvas>
          <!-- 小图 -->
          <canvas
            :width="smallWidth"
            :height="smallHeight"
            ref="smallCanvas"
            class="slider-block"
          ></canvas>
          <div
            :class="`result-mask ${resultMask.class}`"
            :style="{ height: resultMask.height + 'px' }"
          ></div>
          <div class="btn" @click="refresh"></div>

          <!-- 拖动滑块 -->
          <div class="slider-square">
            <div class="box">
              <div
                class="slider-square-icon"
                @mousedown="sliderDown"
                :style="{ left: slideInfo.sliderLeft }"
              ></div>
              <span>{{ slideInfo.sliderText }}</span>
            </div>
          </div>
        </div>
      </div>
    </div>
  </Teleport>
</template>

<script setup lang="ts">
import { ref, reactive, onMounted, watch } from "vue";
const props = defineProps({
  // 大图图源
  bigImg: { type: String, default: "" },
  // 小图图源
  smallImg: { type: String, default: "" },
  //   大图宽度
  bigWidth: { type: Number, default: 0 },
  //   大图高度
  bigHeight: { type: Number, default: 0 },
  //   小图宽度
  smallWidth: { type: Number, default: 0 },
  //   小图高度
  smallHeight: { type: Number, default: 0 },
  //   滑块文字
  sliderText: { type: String, default: "拖动滑块向右>>" },
  //   Y坐标
  posY: { type: Number, default: 0 },
  //   X坐标
  posX: { type: Number, default: 0 },
  //拖动范围误差
  accuracy: { type: Number, default: 5 },
  //   小图的拼图半径
  r: { type: Number, default: 0 },
});
// 大图ref
const bigCanvas = ref(null);
// 大图绘制容器
const bigCanvasCtx = ref(null);
// 小图ref
const smallCanvas = ref(null);
// 小图绘制容器
const smallCanvasCtx = ref(null);
const resultMask = reactive({
  // 结果提示背景色
  class: "",
  height: 0,
});
const slideInfo = reactive({
  sliderLeft: 0, //可拖动滑块的left
  block_x: 0, //拼图最终要滑动的位置x
  block_y: 0, //拼图y位置
  sw: props.smallWidth, //拼图实际宽度 小图宽度+2*半径 + 3（border）
  sliderText: props.sliderText, //滑块提示文字
  bigImg: "",
  smIng: "",
});
const origin = reactive({
  // 鼠标按下初始位置
  originX: 0,
  originY: 0,
});
// 初始化bigCanvas dom
const initDom = () => {
  bigCanvasCtx.value = bigCanvas.value?.getContext("2d");
  smallCanvasCtx.value = smallCanvas.value?.getContext("2d");
};
// 初始化图片
const initImg = () => {
  const bigImg = createImg(() => {
    bigCanvasCtx.value.drawImage(bigImg, 0, 0, props.bigWidth, props.bigHeight);
  }, props.bigImg);
  const smallImg = createImg(() => {
    smallCanvasCtx.value.drawImage(
      smallImg,
      0,
      0,
      props.smallWidth,
      props.smallHeight
    );
  }, props.smallImg);
};

const createImg = (onload, url) => {
  const img = document.createElement("img");
  img.crossOrigin = "Anonymous";
  img.onload = onload;
  img.onerror = () => {
    img.src = url;
  };
  img.src = url;
  return img;
};
// 生命周期
onMounted(() => {
  initDom();
  initImg();
  bindEvents();
});
const slider = ref(false);
// 鼠标按下
const sliderDown = (e: MouseEvent) => {
  slider.value = true;
  slideInfo.sliderText = "";
  origin.originX = e.pageX;
  origin.originY = e.pageY;
};
// 鼠标移动
const sliderMove = (e: MouseEvent) => {
  if (slider.value) {
    const moveX = e.pageX - origin.originX;
    const moveY = e.pageY - origin.originY;
    if (moveX < 0 || moveX + 40 >= props.bigWidth) return false;
    slideInfo.sliderLeft = moveX + "px";
    let blockLeft =
      ((props.bigWidth - slideInfo.sw) / (props.bigWidth - 40)) * moveX;
    smallCanvas.value.style.left = blockLeft + "px";
  }
};
const emit = defineEmits(["sliderJudge", "request-event"]);
// 鼠标松开
const sliderUp = (e: MouseEvent) => {
  if (!slider.value) return false;
  slider.value = false;
  resultMask.height = props.bigHeight / 2;
  const left = parseInt(smallCanvas.value.style.left);
  emit("sliderJudge", left);
};
// 将鼠标移动，鼠标松开事件绑定在dom上
const bindEvents = () => {
  document.addEventListener("mousemove", sliderMove);
  document.addEventListener("mouseup", sliderUp);
  resultMask.height = 0;
  resultMask.class = "";
  slideInfo.sliderLeft = 0;
  smallCanvas.value.style.left = 0;
};
// 刷新图片
const refresh = () => {
  emit("request-event");
};
// 重置/刷新图片
const reset = () => {
  bigCanvasCtx.value.clearRect(0, 0, props.bigWidth, props.bigHeight);
  smallCanvasCtx.value.clearRect(0, 0, props.smallWidth, props.smallHeight);
  slideInfo.sliderText = props.sliderText;
};
// 组件销毁移除鼠标时间
document.removeEventListener("mousemove", sliderMove);
document.removeEventListener("mouseup", sliderUp);
watch(
  () => props.bigImg,
  (newVal) => {
    reset();
    initImg();
  }
);
</script>

<style lang="scss" scoped>
.slide-split {
  position: absolute;
  bottom: 0;
  right: 0;
  left: 0;
  top: 0;
  background-color: rgba(0, 0, 0, 0.6);
  z-index: 999;
}
.slider-container {
  position: absolute;
  left: 50%;
  top: 50%;
  // 避免回流 translateZ(0)
  transform: translate(-50%, -50%) translateZ(0);
  .slider-canvas {
    position: relative;
    .slider-block {
      position: absolute;
      left: 0;
      top: 0;
    }
    .btn {
      position: absolute;
      right: 0;
      top: 0;
      width: 20px;
      height: 20px;
      cursor: pointer;
      background-image: url("@img/login/light.png");
      background-position: 20px;
      background-size: 20px;
      z-index: 999;
      color: #f10909;
      //   background-color: #fff;
    }
    @keyframes result-show {
      0% {
        opacity: 0;
      }
      100% {
        opacity: 0.7;
      }
    }
    .result-mask {
      position: absolute;
      left: 0;
      bottom: 0;
      width: 100%;
      opacity: 0.7;
      &.success {
        background-color: #52ccba;
        animation: result-show 1s;
      }
      &.fail {
        background-color: #f57a7a;
        animation: result-show 1s;
      }
    }
  }
}
.slider-square {
  background-color: #f7f9fa;
  height: 40px;
  line-height: 40px;
  text-align: center;
  border: 1px solid #ddd;
  position: relative;
  margin-top: 12px;
  .slider-square-icon {
    position: absolute;
    top: 0;
    left: 0;
    height: 39px;
    width: 39px;
    background-color: #fff;
    box-shadow: blanchedalmond 0px 0 px 1px 2px;
    cursor: pointer;
    &:hover {
      background-color: rgb(249, 162, 32);
    }
  }
}
</style>
